﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BlueCrest.ConfigManagement.Core.Data;
using BlueCrest.ConfigManagement.Storage.DB.Data;
using BlueCrest.ConfigManagement.Storage.DB.Exceptions;
using ConfigPathEntryEntity = BlueCrest.ConfigManagement.Core.Data.ConfigPathEntryEntity;

namespace BlueCrest.ConfigManagement.Storage.DB.Service
{
    public interface IConfigPathAdapterService
    {
        /// <summary>
        /// Converts the Flat ConfigPathEntity into Treed one
        /// </summary>
        /// <param name="flatEntities">Collection of FlatEntities</param>
        /// <param name="parentEntity">Optional, if provided one, it will try to build the tree using that, otherwise will start from ConfigPathEntity
        /// which has no parent</param>
        /// <returns></returns>
        IEnumerable<ConfigPathTreeEntity> Adapt(List<ConfigPathFlatEntity> flatEntities, ConfigPathFlatEntity parentEntity = null);

        /// <summary>
        /// Converts DB Entries into Entries used by interface
        /// </summary>
        /// <param name="scopes"> </param>
        /// <param name="dbEntries"></param>
        /// <returns></returns>
        IEnumerable<ConfigPathEntryEntity> Adapt(List<ScopeEntity> scopes, List<Data.ConfigPathEntryEntity> dbEntries);
    }

    public class ConfigPathAdapterService : IConfigPathAdapterService
    {
        public IEnumerable<ConfigPathTreeEntity> Adapt(List<ConfigPathFlatEntity> flatEntities, ConfigPathFlatEntity parentEntity = null)
        {
            #region Generating Root Note
            
            var rootFlat = new List<ConfigPathFlatEntity>();

            if (parentEntity == null)
            {
                rootFlat.AddRange(flatEntities.Where(a => a.ParentPathId == 0));
            }
            else
            {
                rootFlat.Add(parentEntity);
            }

            if (rootFlat.Count == 0)
            {
                throw new ParentConfigPathIsNotFoundException();
            }

            var rootTree = new List<ConfigPathTreeEntity>();
            rootFlat.ForEach(a => rootTree.Add(new ConfigPathTreeEntity(a.PathId, a.PathName)));
            
            #endregion

            foreach (ConfigPathTreeEntity rootItem in rootTree)
            {
                AddChildren(rootItem, flatEntities);
            }

            return rootTree;
        }

        public IEnumerable<ConfigPathEntryEntity> Adapt(List<ScopeEntity> scopes, List<Data.ConfigPathEntryEntity> dbEntries)
        {
            var list = new List<ConfigPathEntryEntity>();
            dbEntries.ForEach(a => list.Add(new ConfigPathEntryEntity(a.EntryId, scopes.FirstOrDefault(s => s.ScopeId == a.ScopeId), a.EntryName
                                , a.EntryType, a.EntryValue)));

            return list;
        }

        private void AddChildren(ConfigPathTreeEntity currentItem, List<ConfigPathFlatEntity> allItems)
        {
            //find all children;
            var children = allItems.FindAll(a => currentItem.PathId == a.ParentPathId);

            children.ForEach(a => currentItem.AddChild(a.PathId, a.PathName));
            foreach (var child in currentItem.Children)
            {
                AddChildren(child, allItems);
            }
        }
    }
}
